/*	--- 享元 Flyweight --- 

#	运用【共享技术】有效地支持【大量细粒度的对象】。

========================================================


【享元】（Flyweight）的核心思想很简单：  如果【一个对象实例】一经创建就【不可变】，那么【反复创建相同的实例】就【没有必要】，【直接向调用方】返回一个【共享的实例】就行，这样即【节省内存，又可以减少创建对象的过程，提高运行速度】。


【享元模式】在Java标准库中有很多应用。

我们知道，【包装类型】如【Byte、Integer】都是【不变类】，因此，【反复创建】同一个值相同的包装类型是没有必要的。

以Integer为例，如果我们通过【Integer.valueOf()这个静态工厂方法】创建【Integer实例】，当【传入的int范围】在【-128 ~ +127】之间时， 会直接返回【缓存的Integer实例】： */

// 享元模式
public class Main {
	public static void main(String[] args) throws InterruptedException {
		
		Integer n1 = Integer.valueOf(100);
		Integer n2 = Integer.valueOf(100);

		System.out.println(n1 == n2)； // 地址相同, true
	}
}


/*
对于【Byte】来说，因为它一共【只有256个状态】，所以，通过【Byte.valueOf()】创建的【Byte实例】，全部都是【缓存对象】。

因此，【享元模式】就是通过【工厂方法】创建对象，在【工厂方法内部】，很可能返回【缓存的实例】，而【不是新创建实例】，从而实现【不可变实例的复用】。


#	总是使用工厂方法而不是new操作符创建实例，可获得享元模式的好处。


==========================================================


在实际应用中，【享元模式】主要应用于【缓存】，即【客户端】如果【重复请求】某些对象，【不必每次】查询数据库/读取文件，而是直接【返回 内存中缓存的数据】。

我们以Student为例，设计一个【静态工厂方法】，它在【内部】可以返回【缓存的对象】： */
public class Student {
	private final int id;
	private final String name;

	public Student(int id, String name) {
		this.id = id;
		this.name = name;
	}

	// 持有缓存:
	private static final Map<String, Student> cache = new HashMap<>();

	// 静态工厂方法 -- 创建Student
	public static Student create(int id, String name) {
		String key = id + "\n" + name;

		// 优先查找Cache
		Student std = cache.get(key);

		if (std == null) {
			// 未找到, 创建新对象
			System.out.println(String.format("create new Student(%s, %s)", id, name));

			std = new Student(id, name);

			// 放入缓存
			cache.put(key, std); // HashMap.put(key, std);

		} else {
			// 缓存中存在
			System.out.println(String.format("return cached Student(%s, %s)", std.id, std.name));
		}

		return std;
	}

}

/*
在实际应用中，我们经常使用成熟的缓存库，例如Guava的Cache，因为它提供了最大缓存数量限制、定时过期等实用功能。 

=========================================================

#	练习

使用享元模式实现缓存 */



/*=========================================================


#	----- 享元 Flyweight の 小结 -----
















